package com.test.codec.rsa;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description:
 * @Author: yangzhiwei
 * @Date: 2020/11/19 13:46
 */
public class ORSA {
        public static final String SIGNATURE_ALGORITHM_MD5withRSA = "MD5withRSA";
        public static final String SIGNATURE_ALGORITHM_SHA1withRSA = "SHA1withRSA";
        public static final String PUBLIC_KEY = "RSAPublicKey";
        public static final String PRIVATE_KEY = "RSAPrivateKey";
        private static final String KEY_ALGORITHM = "RSA";

        /**
         * 签名
         *
         * @param data
         * @param privateKey
         * @return
         * @throws Exception
         */
        public byte[] sign(byte[] data, byte[] privateKey) throws Exception
        {
            return sign(data, privateKey, SIGNATURE_ALGORITHM_SHA1withRSA);
        }

        /**
         * 签名
         *
         * @param data
         * @param privateKey
         * @param signatureAlgorithm
         * @return
         * @throws Exception
         */
        public byte[] sign(byte[] data, byte[] privateKey, String signatureAlgorithm)
                throws Exception
        {
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);

            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

            PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

            Signature signature = Signature.getInstance(signatureAlgorithm);
            signature.initSign(priKey);
            signature.update(data);
            return signature.sign();
        }

        /**
         * 验证
         *
         * @param data
         * @param publicKey
         * @param sign
         * @return
         * @throws Exception
         */
        public boolean verify(byte[] data, byte[] publicKey, byte[] sign)
                throws Exception
        {
            return verify(data, publicKey, sign, SIGNATURE_ALGORITHM_SHA1withRSA);
        }

        /**
         * 验证
         *
         * @param data
         * @param publicKey
         * @param sign
         * @param signatureAlgorithm
         * @return
         * @throws Exception
         */
        public boolean verify(byte[] data, byte[] publicKey, byte[] sign,
                              String signatureAlgorithm) throws Exception
        {
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);

            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

            PublicKey pubKey = keyFactory.generatePublic(keySpec);

            Signature signature = Signature.getInstance(signatureAlgorithm);
            signature.initVerify(pubKey);
            signature.update(data);

            return signature.verify(sign);
        }

        /**
         * 公钥加密
         *
         * @param data
         * @param publicKey
         * @return
         * @throws Exception
         */
        public byte[] encryptByPublicKey(byte[] data, byte[] publicKey)
                throws Exception
        {
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key publicK = keyFactory.generatePublic(x509KeySpec);

            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(1, publicK);

            return cipher.doFinal(data);
        }

        /**
         * 私钥加密
         *
         * @param data
         * @param privateKey
         * @return
         * @throws Exception
         */
        public byte[] encryptByPrivateKey(byte[] data, byte[] privateKey)
                throws Exception
        {
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);

            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(1, privateK);
            return cipher.doFinal(data);
        }

        /**
         * 私钥解密
         *
         * @param data
         * @param privateKey
         * @return
         * @throws Exception
         */
        public byte[] decryptByPrivateKey(byte[] data, byte[] privateKey)
                throws Exception
        {
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);

            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(2, privateK);
            return cipher.doFinal(data);
        }

        /**
         * 公钥解密
         *
         * @param data
         * @param publicKey
         * @return
         * @throws Exception
         */
        public byte[] decryptByPublicKey(byte[] data, byte[] publicKey)
                throws Exception
        {
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key publicK = keyFactory.generatePublic(x509KeySpec);

            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(2, publicK);
            return cipher.doFinal(data);
        }

        /**
         * 初始化密钥
         *
         * @return
         * @throws Exception
         */
        public Map<String, byte[]> initKey() throws Exception
        {
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
            keyPairGen.initialize(1024);
            KeyPair keyPair = keyPairGen.generateKeyPair();

            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

            RSAPrivateKey privateKey;
            privateKey = (RSAPrivateKey) keyPair.getPrivate();
            Map<String, byte[]> keyMap = new HashMap<String, byte[]>(2);
            keyMap.put(PUBLIC_KEY, publicKey.getEncoded());
            keyMap.put(PRIVATE_KEY, privateKey.getEncoded());
            return keyMap;
        }

    public static void main(String[] args) {

    }
}
